use core::ops::{Add, BitAnd, BitOr, Not, Shl};


pub trait VolatileHandle {
    fn volatile_write(&mut self, value: Self);

    fn volatile_read(&self) -> Self;

    fn volatile_add(&mut self, value: Self);
}

impl<T: Add<Output = T> + Copy> VolatileHandle for T {
    #[inline(always)]
    fn volatile_add(&mut self, value: Self) {
        let tmp = self.volatile_read();
        self.volatile_write(value + tmp);
    }

    #[inline(always)]
    fn volatile_read(&self) -> Self {
        unsafe { (self as *const Self).read_volatile() }
    }

    #[inline(always)]
    fn volatile_write(&mut self, value: Self) {
        unsafe {
            (self as *mut Self).write_volatile(value);
        }
    }
}


pub trait BitSet {
    fn is_set(self, bit: u8) -> bool;
}

impl<T: BitAnd<Output = T> + PartialEq<T> + From<u8> + Copy + Shl<u8, Output = T>> BitSet for T {
    #[inline(always)]
    fn is_set(self, bit: u8) -> bool {
        let n: T = T::from(1u8) << bit;
        (self & n) != T::from(0)
    }
}

pub trait BitCtrl {
    fn set_bit(&mut self, bit: u8);
    fn clr_bit(&mut self, bit: u8);
}

impl<
        T: BitAnd<Output = T>
            + BitOr<Output = T>
            + Not<Output = T>
            + Copy
            + From<u8>
            + Shl<u8, Output = T>,
    > BitCtrl for T
{
    #[inline(always)]
    fn clr_bit(&mut self, bit: u8) {
        let mask = T::from(1u8) << bit;
        *self = *self & (!mask);
    }

    #[inline(always)]
    fn set_bit(&mut self, bit: u8) {
        let mask = T::from(1u8) << bit;
        *self = *self | mask;
    }
}
